package com.whz.generic.crypt;


import lombok.experimental.UtilityClass;
import org.springframework.util.StringUtils;

import java.util.Arrays;

/**
 * 敏感数据的掩码,参考{@link com.github.houbb.sensitive.core.util.strategy.SensitiveStrategyUtil}
 *
 * @author whz
 */
@UtilityClass
public class MaskUtil {
    private static final int PAD_LIMIT = 8192;
    public static final String SPACE = " ";
    private static final String HYPHEN = "-";

    /**
     * 手机号显示首3末4位，中间用*号隐藏代替，如：138****4213
     *
     * @param mobile 手机号
     * @return 掩码后的手机号
     */
    public static String maskMobile(String mobile) {
        if (StringUtils.isEmpty(mobile) || mobile.length() <= 8) {
            return mobile;
        }
        return wordMask(mobile, 3, 4, "*");
    }

    /**
     * 电话号码显示区号及末4位，中间用*号隐藏代替，如：010****4213
     *
     * @param telephone 座机号
     * @return 掩码后的座机号
     */
    public static String maskTelephone(String telephone) {
        if (StringUtils.isEmpty(telephone)) {
            return telephone;
        }
        String result;
        if (telephone.length() > 8) {
            if (telephone.contains(HYPHEN)) {
                String[] temp = telephone.split(HYPHEN);
                result = temp[0] + "****" + ceilTel(temp[1], 4);
            } else {
                result = telephone.substring(0, 3) + "****" + ceilTel(telephone, 4);
            }
        } else {
            result = "****" + ceilTel(telephone, 4);
        }
        return result;
    }

    private static String ceilTel(String telephone, int i) {
        return telephone.substring(telephone.length() - i);
    }

    /**
     * 身份证号显示首6末4位，中间用4个*号隐藏代替，如：421002****1012
     *
     * @param idCard 省份证
     * @return 掩码后的省份证
     */
    public static String maskIdCard(String idCard) {
        if (StringUtils.isEmpty(idCard)) {
            return idCard;
        }
        return wordMask(idCard, 6, 4, "*");
    }

    /**
     * 银行卡显示首6末4位，中间用4个*号隐藏代替，如：622202****4123
     *
     * @param cardNo 银行卡
     * @return 掩码后的银行卡
     */
    public static String maskBankCard(String cardNo) {
        if (StringUtils.isEmpty(cardNo) || cardNo.length() < 10) {
            return cardNo;
        }
        return wordMask(cardNo, 6, 4, "*");
    }

    /**
     * 邮箱像是前两位及最后一位字符，及@后邮箱域名信息，如：ye****y@163.com
     *
     * @param email 邮箱
     * @return 掩码后的邮箱
     */
    public static String maskEmail(String email) {
        if (StringUtils.isEmpty(email)) {
            return email;
        }
        String[] temp = email.split("@");
        return wordMask(temp[0], 1, 1, "*") + "@" + temp[1];
    }

    /**
     * 三个字掩码，如：张晓明 如：张*明
     * 两个字掩码，如：小明 如：*明
     * 多个字掩码，如：张小明明 如：张**明
     *
     * @param name 姓名
     * @return 掩码后的姓名
     */
    public static String maskName(String name) {
        if (StringUtils.isEmpty(name) || name.length() == 1) {
            return name;
        }
        if (name.length() == 2) {
            return "*" + name.charAt(1);
        }

        return wordMask(name, 1, 1, "*");
    }

    /**
     * Cvv全隐藏，如： ***
     *
     * @param cvv Cvv
     * @return 掩码后的 Cvv
     */
    public static String maskCvv(String cvv) {
        if (StringUtils.isEmpty(cvv)) {
            return cvv;
        }
        return "***";
    }

    /**
     * 对字符串进行脱敏处理 --
     *
     * @param word        被脱敏的字符
     * @param startLength 被保留的开始长度 前余n位
     * @param endLength   被保留的结束长度 后余n位
     * @param pad         填充字符
     */
    public static String wordMask(String word, int startLength, int endLength, String pad) {

        if (startLength + endLength > word.length()) {
            return word;
        }

        String startStr = word.substring(0, startLength);

        String endStr = ceilTel(word, endLength);

        return startStr + leftPad("", word.length() - startLength - endLength, pad) + endStr;

    }


    private static String leftPad(final String str, final int size, String padStr) {
        if (str == null) {
            return null;
        }
        if (StringUtils.isEmpty(padStr)) {
            padStr = SPACE;
        }
        final int padLen = padStr.length();
        final int strLen = str.length();
        final int pads = size - strLen;
        if (pads <= 0) {
            return str;
        }
        if (padLen == 1 && pads <= PAD_LIMIT) {
            return leftPad(str, size, padStr.charAt(0));
        }

        if (pads == padLen) {
            return padStr.concat(str);
        } else if (pads < padLen) {
            return padStr.substring(0, pads).concat(str);
        } else {
            final char[] padding = new char[pads];
            final char[] padChars = padStr.toCharArray();
            for (int i = 0; i < pads; i++) {
                padding[i] = padChars[i % padLen];
            }
            return new String(padding).concat(str);
        }
    }

    private static String leftPad(final String str, final int size, final char padChar) {
        if (str == null) {
            return null;
        }
        final int pads = size - str.length();
        if (pads <= 0) {
            return str;
        }
        if (pads > PAD_LIMIT) {
            return leftPad(str, size, String.valueOf(padChar));
        }
        return repeat(padChar, pads) + str;
    }

    private static String repeat(final char ch, final int repeat) {
        if (repeat <= 0) {
            return "";
        }
        final char[] buf = new char[repeat];
        Arrays.fill(buf, ch);
        return new String(buf);
    }
}